/**
 * Copyright (c) 2014 Microsoft Open Technologies, Inc.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License"); you may
 *    not use this file except in compliance with the License. You may obtain
 *    a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
 *
 *    THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR
 *    CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT
 *    LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS
 *    FOR A PARTICULAR PURPOSE, MERCHANTABILITY OR NON-INFRINGEMENT.
 *
 *    See the Apache Version 2.0 License for specific language governing
 *    permissions and limitations under the License.
 *
 *    Microsoft would like to thank the following companies for their review and
 *    assistance with these files: Intel Corporation, Mellanox Technologies Ltd,
 *    Dell Products, L.P., Facebook, Inc
 *
 * @file    sai.h
 *
 * @brief   This module defines an entry point into Switch Abstraction Interface (SAI)
 */

#if !defined (__SAI_H_)
#define __SAI_H_

#include "message.h"
#include "saitypes.h"
#include "saistatus.h"
#include "saiacl.h"
#include "saibuffer.h"
#include "saifdb.h"
#include "saihash.h"
#include "saihostif.h"
#include "sailag.h"
#include "saimirror.h"
#include "saineighbor.h"
#include "sainexthopgroup.h"
#include "sainexthop.h"
#include "saiobject.h"
#include "saipolicer.h"
#include "saiport.h"
#include "saiqosmap.h"
#include "saiqueue.h"
#include "sairoute.h"
#include "saivirtualrouter.h"
#include "sairouterinterface.h"
#include "saisamplepacket.h"
#include "saischedulergroup.h"
#include "saischeduler.h"
#include "saistp.h"
#include "saiswitch.h"
#include "saitunnel.h"
#include "saiudf.h"
#include "saivlan.h"
#include "saiwred.h"
#include "saibridge.h"
#include "sail2mc.h"
#include "saiipmc.h"
#include "sairpfgroup.h"
#include "sail2mcgroup.h"
#include "saiipmcgroup.h"
#include "saimcastfdb.h"

/**
 * @defgroup SAI SAI - Entry point specific API definitions.
 *
 * @{
 */

/**
 * @brief Defined API sets have assigned ID's.
 *
 * If specific API method table changes in any way (method signature, number of
 * methods), a new ID needs to be created (e.g. VLAN2) and old API still may
 * need to be supported for compatibility with older adapter hosts.
 */
typedef enum _sai_api_t
{
    SAI_API_UNSPECIFIED      =  0, /**< unspecified API */
    SAI_API_SWITCH           =  1, /**< sai_switch_api_t */
    SAI_API_PORT             =  2, /**< sai_port_api_t */
    SAI_API_FDB              =  3, /**< sai_fdb_api_t */
    SAI_API_VLAN             =  4, /**< sai_vlan_api_t */
    SAI_API_VIRTUAL_ROUTER   =  5, /**< sai_virtual_router_api_t */
    SAI_API_ROUTE            =  6, /**< sai_route_api_t */
    SAI_API_NEXT_HOP         =  7, /**< sai_next_hop_api_t */
    SAI_API_NEXT_HOP_GROUP   =  8, /**< sai_next_hop_group_api_t */
    SAI_API_ROUTER_INTERFACE =  9, /**< sai_router_interface_api_t */
    SAI_API_NEIGHBOR         = 10, /**< sai_neighbor_api_t */
    SAI_API_ACL              = 11, /**< sai_acl_api_t */
    SAI_API_HOSTIF           = 12, /**< sai_hostif_api_t */
    SAI_API_MIRROR           = 13, /**< sai_mirror_api_t */
    SAI_API_SAMPLEPACKET     = 14, /**< sai_samplepacket_api_t */
    SAI_API_STP              = 15, /**< sai_stp_api_t */
    SAI_API_LAG              = 16, /**< sai_lag_api_t */
    SAI_API_POLICER          = 17, /**< sai_policer_api_t */
    SAI_API_WRED             = 18, /**< sai_wred_api_t */
    SAI_API_QOS_MAP          = 19, /**< sai_qos_map_api_t */
    SAI_API_QUEUE            = 20, /**< sai_queue_api_t */
    SAI_API_SCHEDULER        = 21, /**< sai_scheduler_api_t */
    SAI_API_SCHEDULER_GROUP  = 22, /**< sai_scheduler_group_api_t */
    SAI_API_BUFFER           = 23, /**< sai_buffer_api_t */
    SAI_API_HASH             = 24, /**< sai_hash_api_t */
    SAI_API_UDF              = 25, /**< sai_udf_api_t */
    SAI_API_TUNNEL           = 26, /**< sai_tunnel_api_t */
    SAI_API_L2MC             = 27, /**< sai_l2mc_api_t */
    SAI_API_IPMC             = 28, /**< sai_ipmc_api_t */
    SAI_API_RPF_GROUP        = 29, /**< sai_rpf_group_api_t */
    SAI_API_L2MC_GROUP       = 30, /**< sai_l2mc_group_api_t */
    SAI_API_IPMC_GROUP       = 31, /**< sai_ipmc_group_api_t */
    SAI_API_MCAST_FDB        = 32, /**< sai_mcast_fdb_api_t */
    SAI_API_BRIDGE           = 33, /**< sai_bridge_api_t */
    SAI_API_MAX              = 34, /**< total number of apis */
} sai_api_t;

/**
 * @brief Defines log level
 */
typedef enum _sai_log_level_t
{
    /** Log Level Debug */
    SAI_LOG_LEVEL_DEBUG            = 0,

    /** Log Level Info */
    SAI_LOG_LEVEL_INFO             = 1,

    /** Log Level Notice */
    SAI_LOG_LEVEL_NOTICE           = 2,

    /** Log level Warning */
    SAI_LOG_LEVEL_WARN             = 3,

    /** Log Level Error */
    SAI_LOG_LEVEL_ERROR            = 4,

    /** Log Level Critical */
    SAI_LOG_LEVEL_CRITICAL         = 5

} sai_log_level_t;

typedef const char* (*sai_profile_get_value_fn)(
        _In_ sai_switch_profile_id_t profile_id,
        _In_ const char *variable);

typedef int (*sai_profile_get_next_value_fn)(
        _In_ sai_switch_profile_id_t profile_id,
        _Out_ const char** variable,
        _Out_ const char** value);

/**
 * @brief Method table that contains function pointers for services exposed by
 * adapter host for adapter.
 */
typedef struct _service_method_table_t
{
    /**
     * @brief Get variable value given its name
     */
    sai_profile_get_value_fn        profile_get_value;

    /**
     * @brief Enumerate all the K/V pairs in a profile.
     *
     * Pointer to NULL passed as variable restarts enumeration. Function
     * returns 0 if next value exists, -1 at the end of the list.
     */
    sai_profile_get_next_value_fn   profile_get_next_value;

} service_method_table_t;

/**
 * @brief Adapter module initialization call
 *
 * This is NOT for SDK initialization.
 *
 * @param[in] flags Reserved for future use, must be zero
 * @param[in] services Methods table with services provided by adapter host
 *
 * @return #SAI_STATUS_SUCCESS on success Failure status code on error
 */
sai_status_t sai_api_initialize(
        _In_ uint64_t flags,
        _In_ const service_method_table_t* services);

/**
 * @brief Retrieve a pointer to the C-style method table for desired SAI
 * functionality as specified by the given sai_api_id.
 *
 * @param[in] sai_api_id SAI API ID
 * @param[out] api_method_table Caller allocated method table The table must
 * remain valid until the sai_api_uninitialize() is called
 *
 * @return #SAI_STATUS_SUCCESS on success Failure status code on error
 */
sai_status_t sai_api_query(
        _In_ sai_api_t sai_api_id,
        _Out_ void** api_method_table);

/**
 * @brief Uninitialize adapter module. SAI functionalities,
 * retrieved via sai_api_query() cannot be used after this call.
 *
 * @return #SAI_STATUS_SUCCESS on success Failure status code on error
 */
sai_status_t sai_api_uninitialize(void);

/**
 * @brief Set log level for SAI API module. The default log level is #SAI_LOG_LEVEL_WARN
 *
 * @param[in] sai_api_id SAI API ID
 * @param[in] log_level Log level
 *
 * @return #SAI_STATUS_SUCCESS on success Failure status code on error
 */
sai_status_t sai_log_set(
        _In_ sai_api_t sai_api_id,
        _In_ sai_log_level_t log_level);

/**
 * @brief Query SAI object type.
 *
 * @param[in] sai_object_id Object id
 *
 * @return #SAI_OBJECT_TYPE_NULL when sai_object_id is not valid.
 * Otherwise, return a valid SAI object type SAI_OBJECT_TYPE_XXX
 */
sai_object_type_t sai_object_type_query(
        _In_ sai_object_id_t sai_object_id);

/**
 * @brief Query SAI switch id.
 *
 * @param[in] sai_object_id Object id
 *
 * @return #SAI_NULL_OBJECT_ID when sai_object_id is not valid.
 * Otherwise, return a valid SAI_OBJECT_TYPE_SWITCH object on which
 * provided object id belongs. If valid switch id object is provided
 * as input parameter it should return itself.
 */
sai_object_id_t sai_switch_id_query(
        _In_ sai_object_id_t sai_object_id);

/**
 * @brief Generate dump file. The dump file may include SAI state information and vendor SDK information.
 *
 * @param[in] dump_file_name Full path for dump file
 *
 * @return #SAI_STATUS_SUCCESS on success Failure status code on error
 */
sai_status_t sai_dbg_generate_dump(
        _In_ const char *dump_file_name);

/**
 * @brief Get SAI object type resource availability.
 *
 * @param[in] switch_id SAI Switch object id
 * @param[in] object_type SAI object type
 * @param[in] attr_count Number of attributes
 * @param[in] attr_list List of attributes that to distinguish resource
 * @param[out] count Available objects left
 *
 * @return #SAI_STATUS_NOT_SUPPORTED if the given object type does not support resource accounting.
 * Otherwise, return #SAI_STATUS_SUCCESS.
 */
sai_status_t sai_object_type_get_availability(
        _In_ sai_object_id_t switch_id,
        _In_ sai_object_type_t object_type,
        _In_ uint32_t attr_count,
        _In_ const sai_attribute_t *attr_list,
        _Out_ uint64_t *count);

/**
 * @}
 */

//add message.h
#ifndef _MESSAGES_H_
#define _MESSAGES_H_ 1

#include <stdint.h>

#define P4_VERSION 1
#define true 1
#define false 0
#define MAX_MACS 60000

struct p4_header {
	uint8_t version;	/* version */
	uint8_t type;		/* P4T constants */
	uint16_t length;	/* Length including this header */
	uint32_t xid;		/* Transaction ID */
};


enum p4_type {
	/* Immutable messages */
	P4T_HELLO = 0,
	P4T_ERROR = 1,
	P4T_ECHO_REQUEST = 2,
	P4T_ECHO_REPLY = 3,
	P4T_SUCCESS = 4,
	P4T_CTRL_INITIALIZED = 5,

	/* Switch informations */	
	P4T_GET_TABLE_DEFINITIONS = 100,
	P4T_GET_TABLE_COUNTERS = 101,
	P4T_GET_TABLE_ENTRIES = 102,

	/* Controller commands */
	P4T_SET_DEFAULT_ACTION = 103,
	P4T_ADD_TABLE_ENTRY = 104, /*with and without selector (action, action_profile)*/
	P4T_MODIFY_TABLE_ENTRY = 105,
	P4T_REMOVE_TABLE_ENTRY = 106,
	P4T_DROP_TABLE_ENTRIES = 107,
	P4T_ADD_AP_MEMBER = 108,
	P4T_REMOVE_AP_MEMBER = 109,
   
        /* Controller COUNTER  commands */
        P4T_MODIFY_COUNTER_ENTRY = 111,
        P4T_GET_COUNTER_ENTRIES = 112,
        P4T_RESET_COUNTER_ENTRY = 113,

	/* Digest passed */
	P4T_DIGEST = 110,

        /*packet in/out*/
	P4T_PACKET_OUT = 50,
	P4T_PACKET_IN = 51
};

struct p4_hello {
	struct p4_header header;
	/* Hello element list */
	struct p4_hello_elem_header *elements; /* List of elements - 0 or more */
};

/* Hello elements types.
*/
enum p4_hello_elem_type {
	OFPHET_VERSIONBITMAP = 1 /* Bitmap of version supported. */
};

/* Common header for all Hello Elements */
struct p4_hello_elem_header {
	uint16_t type; /* One of OFPHET_*. */
	uint16_t length; /* Length in bytes of the element,
including this header, excluding padding. */
};

/* Version bitmap Hello Element */
struct p4_hello_elem_versionbitmap {
	uint16_t type; /* OFPHET_VERSIONBITMAP. */
	uint16_t length; /* Length in bytes of this element,
including this header, excluding padding. */
	/* Followed by:
		* - Exactly (length - 4) bytes containing the bitmaps, then
		* - Exactly (length + 7)/8*8 - (length) (between 0 and 7)
		* bytes of all-zero bytes */
	uint32_t* bitmaps; /* List of bitmaps - supported versions */
};/* Version bitmap Hello Element */

struct p4_error {
	struct p4_header header;
	uint16_t error_code;
};

struct p4_success {
	struct p4_header header;
	uint32_t id;
};

#define P4_MAX_TABLE_NAME_LEN 32
#define P4_MAX_FIELD_NAME_LEN 32
#define P4_MAX_ACTION_NAME_LEN 32

enum p4_field_match_type {
	P4_FMT_EXACT = 0,
	P4_FMT_TERNARY = 1,
	P4_FMT_LPM = 2,
	P4_FMT_RANGE = 3,
	P4_FMT_VALID = 4
};

struct p4_field_match_desc {
	char name[P4_MAX_FIELD_NAME_LEN];
	uint8_t type;
};

enum p4_support_timeout {
	P4_STO_FALSE = 0,
	P4_STO_TRUE = 1
};

enum p4_action_type {
	P4_AT_ACTION = 0,
	P4_AT_ACTION_PROFILE = 1
};

struct p4_table_action_desc {
	uint8_t type;
	char name[P4_MAX_ACTION_NAME_LEN];
};

struct p4_table_definition {
	struct p4_header header;
	char name[P4_MAX_TABLE_NAME_LEN];
	uint8_t reads;
	uint16_t min_size;
	uint16_t max_size;
	uint16_t size;
	uint8_t support_timeout;
	uint8_t read_size; /* number of rules in reads */
	uint8_t action_size; /* number of actions */
	/* struct p4_field_match_desc[read_size]; */
	/* struct p4_table_action_desc[action_size]; */
};


#define MAX_ACTION_PARAMETER_NAME_LENGTH 64
#define MAX_ACTION_PARAMETER_BITMAP_LENGTH 64
struct p4_action_parameter {
	char name[MAX_ACTION_PARAMETER_NAME_LENGTH];
	uint32_t length; /* TODO: How can we figure this out?????Controller should know this in advance! P4 does not handle it. */
	char bitmap[MAX_ACTION_PARAMETER_BITMAP_LENGTH];
};

/* TODO: action_profiles can also be set as default action */

struct p4_action {
        struct p4_table_action_desc description; /* Action name of action profile name */
        uint8_t param_size;
	/* struct p4_action_parameter params[param_size]; */
};

struct p4_set_default_action {
	struct p4_header header;
	char table_name[P4_MAX_TABLE_NAME_LEN];
	struct p4_action action; /* Action or action profile instance */
};

struct p4_field_match_header {
	char name[P4_MAX_FIELD_NAME_LEN];
	uint8_t type; /* p4_field_match_type */
};

#define MAX_FIELD_LENGTH 256

struct p4_field_match_lpm {
	struct p4_field_match_header header;
	uint16_t prefix_length;
	char bitmap[MAX_FIELD_LENGTH];
};

struct p4_field_match_exact {
	struct p4_field_match_header header;
        uint16_t length;
	char bitmap[MAX_FIELD_LENGTH];
};

struct p4_field_match_range {
	struct p4_field_match_header header;
        uint16_t length;
	uint8_t is_signed; /* boolean variable */
        char min_bitmap[MAX_FIELD_LENGTH];
	char max_bitmap[MAX_FIELD_LENGTH];
};

struct p4_field_match_ternary {
	struct p4_field_match_header header;
        uint16_t length;
	uint16_t priority;
        char bitmap[MAX_FIELD_LENGTH];
	char mask[MAX_FIELD_LENGTH];
};

struct p4_field_match_valid {
	struct p4_field_match_header header;
        uint16_t length;
	uint8_t is_valid; /* could be true or false - boolean variable */
        char bitmap[MAX_FIELD_LENGTH];
};

struct p4_add_table_entry {
	struct p4_header header;
	char table_name[P4_MAX_TABLE_NAME_LEN];
	uint8_t read_size;
	/* struct p4_field_match matches[read_size]; */
	/* struct p4_action; */
};

#define P4_MAX_FIELD_LIST_NAME_LEN 128
#define P4_MAX_FIELD_NAME_LENGTH 128
#define P4_MAX_FIELD_VALUE_LENGTH 32

struct p4_digest_field {
        char name[P4_MAX_FIELD_NAME_LENGTH];
        uint32_t length; /* TODO: How can we figure this out?????Controller should know this in advance! P4 does not handle it. */
        char value[P4_MAX_FIELD_VALUE_LENGTH];	
};

struct p4_digest {
	struct p4_header header;
	char field_list_name[P4_MAX_FIELD_LIST_NAME_LEN];
	uint8_t list_size;
	/* struct p4_digest_field field_list[list_size]; */
};

struct p4_header *create_p4_header(char* buffer, uint16_t offset, uint16_t maxlength);
struct p4_header *unpack_p4_header(char* buffer, uint16_t offset);
void check_p4_header( struct p4_header* a, struct p4_header* b);
struct p4_header* netconv_p4_header(struct p4_header* m);

struct p4_add_table_entry* create_p4_add_table_entry(char* buffer, uint16_t offset, uint16_t maxlength);
struct p4_field_match_lpm* add_p4_field_match_lpm(struct p4_add_table_entry* add_table_entry, uint16_t maxlength);
struct p4_add_table_entry* unpack_p4_add_table_entry(char* buffer, uint16_t offset);
struct p4_field_match_header* unpack_p4_field_match_header(char* buffer, uint16_t offset);
struct p4_field_match_lpm* unpack_p4_field_match_lpm(char* buffer, uint16_t offset);
struct p4_field_match_exact* add_p4_field_match_exact(struct p4_add_table_entry* add_table_entry, uint16_t maxlength);
struct p4_field_match_exact* unpack_p4_field_match_exact(char* buffer, uint16_t offset);
struct p4_field_match_range* add_p4_field_match_range(struct p4_add_table_entry* add_table_entry, uint16_t maxlength);
struct p4_field_match_range* unpack_p4_field_match_range(char* buffer, uint16_t offset);
struct p4_field_match_valid* add_p4_field_match_valid(struct p4_add_table_entry* add_table_entry, uint16_t maxlength);
struct p4_field_match_valid* unpack_p4_field_match_valid(char* buffer, uint16_t offset);
struct p4_field_match_ternary* add_p4_field_match_ternary(struct p4_add_table_entry* add_table_entry, uint16_t maxlength);
struct p4_field_match_ternary* unpack_p4_field_match_ternary(char* buffer, uint16_t offset);
struct p4_action* add_p4_action(struct p4_header* header, uint16_t maxlength);
struct p4_action* unpack_p4_action(char* buffer, uint16_t offset);
struct p4_action_parameter* add_p4_action_parameter(struct p4_header* header, struct p4_action* action, uint16_t maxlength);
struct p4_action_parameter* unpack_p4_action_parameter(char* buffer, uint16_t offset);
struct p4_set_default_action* create_p4_set_default_action(char* buffer, uint16_t offset, uint16_t maxlength);
struct p4_set_default_action* unpack_p4_set_default_action(char* buffer, uint16_t offset);
struct p4_digest* create_p4_digest(char* buffer, uint16_t offset, uint16_t maxlength);
struct p4_digest* unpack_p4_digest(char* buffer, uint16_t offset);
struct p4_digest_field* add_p4_digest_field(struct p4_digest* digest, uint16_t maxlength);
struct p4_digest_field* unpack_p4_digest_field(char* buffer, uint16_t offset);

struct p4_field_match_lpm* netconv_p4_field_match_lpm(struct p4_field_match_lpm* m);
struct p4_field_match_exact* netconv_p4_field_match_exact(struct p4_field_match_exact* m);
struct p4_field_match_range* netconv_p4_field_match_range(struct p4_field_match_range* m);
struct p4_field_match_ternary* netconv_p4_field_match_ternary(struct p4_field_match_ternary* m);
struct p4_field_match_valid* netconv_p4_field_match_valid(struct p4_field_match_valid* m);
struct p4_digest_field* netconv_p4_digest_field(struct p4_digest_field* m);
struct p4_action* netconv_p4_action( struct p4_action* m);
struct p4_action_parameter* netconv_p4_action_parameter(struct p4_action_parameter* m);
struct p4_set_default_action* netconv_p4_set_default_action(struct p4_set_default_action* m);
struct p4_field_match_header* netconv_p4_field_match_complex(struct p4_field_match_header *m, int* size);
struct p4_add_table_entry* netconv_p4_add_table_entry(struct p4_add_table_entry* m);

#endif


#endif /** __SAI_H_ */
